home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / readers / nn-tk.001 / nn-tk~ / nn / proto.c < prev    next >
C/C++ Source or Header  |  1995-07-25  |  4KB  |  189 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Master/slave communication and locking.
  5.  */
  6.  
  7. #include "config.h"
  8. #include <signal.h>
  9. #include <errno.h>
  10. #include <pwd.h>
  11. #include "proto.h"
  12.  
  13. /* proto.c */
  14.  
  15. static void write_lock __APROTO((char *lock, char *operation));
  16. static int read_lock __APROTO((char *lock));
  17.  
  18.  
  19. #ifndef ACCOUNTING
  20. #ifdef AUTHORIZE
  21. #define ACCOUNTING
  22. #endif
  23. #endif
  24.  
  25. import char *master_directory, *db_directory;
  26.  
  27. #define HOSTBUF 80
  28. export char proto_host[HOSTBUF];    /* host having the lock */
  29.  
  30. /*
  31.  *    When setting a lock, we must check a little later that
  32.  *    we really got the lock set, i.e. that another process
  33.  *    didn't set it at the same time!
  34.  */
  35.  
  36. #define LOCK_SAFETY    5    /* seconds */
  37.  
  38. /*
  39.  *    proto_lock(program, mode)
  40.  *
  41.  *    Returns:
  42.  *    -1    Not running.
  43.  *    0    Running, no permission (PL_WAKEUP_SOFT)
  44.  *    0    Lock set (PL_SET)
  45.  *    1    Lock not set (PL_SET)  (another is running)
  46.  *    1       Locked and running (PL_WAKEUP)
  47.  *    pid    Locked and running (PL_CHECK)
  48.  */
  49.  
  50. static void
  51. write_lock(lock, operation)
  52. char *lock, *operation;
  53. {
  54.     FILE *m_pid;
  55.     char host[HOSTBUF];
  56.  
  57.     m_pid = open_file(lock, OPEN_CREATE);
  58.     if (m_pid == NULL)
  59.     sys_error("Cannot %s lock file: %s", operation, lock);
  60.     nn_gethostname(host, HOSTBUF);
  61.     fprintf(m_pid, "%d\n%s\n", process_id, host);
  62.     fclose(m_pid);
  63. }
  64.  
  65. static int read_lock(lock)
  66. char *lock;
  67. {
  68.     FILE *m_pid;
  69.     char host[HOSTBUF];
  70.     char pid[10];
  71.     
  72.     pid[0] = NUL;
  73.     proto_host[0] = NUL;
  74.     
  75.     m_pid = open_file(lock, OPEN_READ);
  76.     if (m_pid == NULL) return -2;    /* no lock */
  77.     fgets(pid, 10, m_pid);
  78.     fgets(proto_host, HOSTBUF, m_pid);
  79.     fclose(m_pid);
  80.  
  81.     if (pid[0] == NUL) return 0;    /* corrupted lock */
  82.     
  83.     if (proto_host[0] != NUL) {
  84.     substchr(proto_host, NL, NUL);
  85.     nn_gethostname(host, HOSTBUF);
  86.     if (strncmp(proto_host, host, HOSTBUF) != 0)
  87.         return -1;            /* locked by another host */
  88.     proto_host[0] = NUL;
  89.     }
  90.     return atoi(pid);
  91. }
  92.  
  93. int
  94. proto_lock(prog, command)
  95. int prog;
  96. int command;
  97. {
  98.     int try, pid;
  99.     char *lock = NULL;
  100.  
  101.     switch (prog) {
  102.      case I_AM_SPEW:
  103.     lock = relative(master_directory, "WPID");
  104.     break;
  105. #ifdef ACCOUNTING
  106.      case I_AM_ACCT:
  107.     lock = relative(db_directory, "LCK..acct");
  108.     break;
  109. #endif
  110.      case I_AM_NN:
  111.     lock = relative(nn_directory, "LOCK");
  112.     break;
  113.      default:
  114.     sys_error("Invalid LOCK prog");
  115.     }
  116.  
  117.     if (command == PL_TRANSFER) {
  118.     write_lock(lock, "transfer");
  119.     return 1;
  120.     }
  121.  
  122.     if (command == PL_CLEAR)
  123.     goto rm_lock;
  124.  
  125.     try = 1;
  126.  again:
  127.  
  128.     switch (pid = read_lock(lock)) {
  129.      case -2:
  130.     goto no_lock;
  131.      case -1:            /* wrong host */
  132.     return 1;
  133.      case 0:
  134.      case 1:
  135.      case 2:            /* corrupted lock file */
  136.     if (who_am_i == I_AM_NN) goto rm_lock;
  137.     if (--try < 0) goto rm_lock;
  138.     sleep(LOCK_SAFETY);    /* maybe it is being written */
  139.     goto again;
  140.      default:
  141.     break;
  142.     }    
  143.  
  144.     if (kill(pid, command == PL_TERMINATE ? SIGHUP : SIGALRM) == 0) {
  145.     switch (command) {
  146.      case PL_SET_QUICK:
  147.         sleep(1);
  148.         goto again;
  149.  
  150.      case PL_SET_WAIT:
  151.      case PL_CLEAR_WAIT:
  152.         sleep(30);
  153.         goto again;
  154.  
  155.      case PL_CHECK:
  156.         return pid;
  157.  
  158.      default:
  159.         return 1;
  160.     }
  161.     }
  162.  
  163.     if (command == PL_CHECK)
  164.     return (errno == EPERM) ? pid : -1;
  165.     if (command == PL_WAKEUP_SOFT)
  166.     return (errno == EPERM) ? 0 : -1;
  167.  
  168.     /* lock file contains a non-existing process, or a process with */
  169.     /* wrong owner, ie. neither master or expire, so remove it */
  170.  
  171.  rm_lock:
  172.     unlink(lock);
  173.  
  174.  no_lock:
  175.     if (command != PL_SET && command != PL_SET_QUICK && command != PL_SET_WAIT)
  176.     return -1;
  177.  
  178.     write_lock(lock, "create");
  179.  
  180.     /* a user will not start nn twice at the exact same time! */
  181.     if (who_am_i == I_AM_NN || command == PL_SET_QUICK) return 0;
  182.  
  183.     sleep(LOCK_SAFETY);
  184.  
  185.     if (read_lock(lock) != process_id)
  186.     return 1;    /* somebody stole the lock file */
  187.     return 0;     /* lock is set */
  188. }
  189.